// @Author EthanScriptOn
// @Desc
package config_parser

import (
	"errors"
	"fmt"
	"gitee.com/fatzeng/srf_switch_basic_components/node"
	"gitee.com/fatzeng/srf_switch_config/config_context"
	"gitee.com/fatzeng/srf_switch_config/config_define"
	"gitee.com/fatzeng/srf_switch_protocol/protocol/log"
)

type FundamentalRepeatParseConfigurator struct {
	ResourceParser
	finalPaths []string
}

func (f *FundamentalRepeatParseConfigurator) GetDuplicateLoadingRuleInstanceList() ([]*DuplicateLoadingList, error) {
	duplicateLoadingRuleInstance, err := duplicateLoadingRule.Get()
	if err != nil {
		return nil, err
	}
	duplicateLoadingRuleInstanceList, ok := duplicateLoadingRuleInstance.([]*DuplicateLoadingList)
	if !ok {
		return nil, fmt.Errorf("the result type obtained at %v  %v position is incorrect need []*DuplicateLoadingList", config_define.ParserPositionTag, config_define.DuplicateLoadingRuleInitTag)
	}
	if len(duplicateLoadingRuleInstanceList) == 0 {
		return nil, errors.New("corresponding duplicate loading rules must be specified")
	}
	return duplicateLoadingRuleInstanceList, nil
}

func GenerateFundamentalRepeatParseConfigurator(resourceParser ResourceParser) (*FundamentalRepeatParseConfigurator, error) {
	if resourceParser == nil {
		return nil, errors.New("need to provide a resourceParser")
	}
	return &FundamentalRepeatParseConfigurator{
		ResourceParser: resourceParser,
	}, nil
}

func (f *FundamentalRepeatParseConfigurator) Parse(ctx *config_context.ConfigInitializationContext, unresolvedData interface{}) error {
	return f.ResourceParser.Parse(ctx, unresolvedData)
}

func (f *FundamentalRepeatParseConfigurator) ParsePrepare(ctx *config_context.ConfigInitializationContext) error {
	return f.ResourceParser.ParsePrepare(ctx)
}

func (f *FundamentalRepeatParseConfigurator) ParseDoMore(ctx *config_context.ConfigInitializationContext) error {
	return f.ResourceParser.ParseDoMore(ctx)
}

func (f *FundamentalRepeatParseConfigurator) StageParseResultDoMore(ctx *config_context.ConfigInitializationContext) error {
	duplicateLoadingRuleInstanceList, err := f.GetDuplicateLoadingRuleInstanceList()
	if err != nil {
		return err
	}
	parseResult, err := ctx.GetRecentResultList(node.TAIL)
	if err != nil {
		return err
	}
	groupResult := parseResult.GetGroupResult()
	f.finalPaths, err = f.executeDuplicateLoadingFun(ctx, groupResult, duplicateLoadingRuleInstanceList)
	if err != nil {
		return err
	}
	if err = f.RepeatParse(ctx); err != nil {
		return err
	}
	return f.ResourceParser.StageParseResultDoMore(ctx)
}

func (f *FundamentalRepeatParseConfigurator) RepeatParse(ctx *config_context.ConfigInitializationContext) error {
	originalFilePath, err := ctx.GetFilePath()
	if err = f.startReloadingRepeatedly(ctx, f.finalPaths); err != nil {
		return err
	}
	if err = ctx.SetFilePath(originalFilePath); err != nil {
		return err
	}
	return nil
}

func (f *FundamentalRepeatParseConfigurator) startReloadingRepeatedly(ctx *config_context.ConfigInitializationContext, finalPaths []string) error {
	for _, path := range finalPaths {
		if err := ctx.SetFilePath(path); err != nil {
			return err
		}
		if err := StartParse(ctx); err != nil {
			return err
		}
	}
	return nil
}

func (f *FundamentalRepeatParseConfigurator) executeDuplicateLoadingFun(ctx *config_context.ConfigInitializationContext, parseResult map[config_define.NodeElemType]interface{}, duplicateLoadingRuleInstanceList []*DuplicateLoadingList) ([]string, error) {
	finalPaths := make([]string, 0)
	for _, loadingRule := range duplicateLoadingRuleInstanceList {
		segmentVal, ok := parseResult[loadingRule.NodeElemType]
		if !ok {
			log.Logger().Warn("duplicate loading rule %v does not exist in the parsing result", loadingRule.NodeElemType)
			continue
		}
		loadingFuncPaths, err := loadingRule.CustomizedDuplicateLoadingFunc(ctx, segmentVal)
		if err != nil {
			return nil, err
		}
		finalPaths = append(finalPaths, loadingFuncPaths...)
	}
	return finalPaths, nil
}

func (f *FundamentalRepeatParseConfigurator) StageParseResult(ctx *config_context.ConfigInitializationContext) error {
	return f.ResourceParser.StageParseResult(ctx)
}

func (f *FundamentalRepeatParseConfigurator) GetStageParseResult(ctx *config_context.ConfigInitializationContext) interface{} {
	return f.ResourceParser.GetStageParseResult(ctx)
}
